package mf.trees;

/**
 * Represents a rule of a tree grammar.
 * 
 * @author Maik Funkat
 */
public class Rule {
	
	private String label;
	private Integer[] childs;

	/** Constructs a new rule.
	   
	   A rule is of type 1, if it has one of the two following forms:
	   <ul>
	     <li>A -> B(C)</li>
	     <li>A(x) -> B(C(x))</li>
	   </ul>
	   Thus, we don't have a label and treat the left nonterminal as 
	   first child, the right nonterminal as second child. If the rule 
	   has a parameter x, it is our third child.
	   
	   A rule is of type 2, if it has one of the three following forms:
	   <ul>
	     <li>A -> a</li>
	     <li>A(x) -> f(x, B)</li>
	     <li>A -> f(B, x)</li>
	   </ul>
	   Thus, we have a label and, if it is a terminal symbol <i>g</i> of rank 
	   &gt; 1, our children are the children of <i>g</i>.
	*/
	public Rule(String[] aIn) {
		//if rule is of type 1
		if(aIn[0].matches("\\d+")) {
			label = null;
			childs = new Integer[aIn.length];
			
			for(int i=0; i<aIn.length; i++) {
				if(aIn[i].equals("x"))
					childs[i] = 0;
				else 
					childs[i] = Integer.parseInt(aIn[i]);
			}
		} else {	//rule is of type 2
			label = aIn[0];
			childs = new Integer[aIn.length-1];
			
			for(int i=1; i<aIn.length; i++)
				if(aIn[i].equals("x"))
					childs[i-1] = 0;
				else
					childs[i-1] = Integer.parseInt(aIn[i]);
		}
	}

	/** Returns true, if the rule contains the parameter x. */
	public boolean hasParameter() {
		for(int i=0; i<childs.length; i++)
			if(childs[i] == 0)
				return true;
		
		return false;
	}
	
	/** Returns a string representation of the rule. */
	public String toString() {
		String ret = "";
		
		if(label != null) {
			if(childs.length == 0)
				return label;
			
			ret += label + "(";
			
			for(int i=0; i<childs.length; i++) {
				if(childs[i] == 0)
					ret += "x";
				else
					ret += "A_"+childs[i];
				
				if(i < childs.length-1)
					ret += ", ";
			}
			
			return ret + ")";
		} else 
			return "A_"+childs[0] + "(A_"+childs[1]+(hasParameter() ? "(x)" : "")+")";
	}

	/** Returns the i-th child of the rule. */
	public Integer child(int i) {
		return (i>=0 && i<childs.length ? childs[i] : -1);
	}

	/** Returns the number of children. */
	public int childs() {
		return childs.length;
	}
	
	/** Returns the label of the rule. */
	public String label() {
		return label;
	}
	
	/** Returns true, if the rule is of type 2. */
	public boolean isType2() {
		return !(label == null);
	}
}